<template>
    <div class="container">
        <a-segmented v-model:value="tabActive" block :options="tab" />
        <br />
        <br />
        <div v-show="tabActive == tab[0]">
            <template v-if="fileList.length > 0">
                <!-- 选择文件后 -->
                <a-flex justify="flex-start" gap="middle" horizontal class="upload-component">
                    <a-flex>
                        <PlaySquareOutlined style="font-size: 50px;" />
                    </a-flex>
                    <a-flex style="width: 100%;" gap="small" vertical>
                        <span>{{ fileList[0].name }}</span>
                        <span>{{ uploadState }}</span>
                        <a-progress style="width: 100%;" :percent="uploadPercent" :status="uploadProgressStatus" />
                    </a-flex>
                </a-flex>

                <br>
                <br>

                <!-- 投稿表单控件 -->
                <a-form :model="work" :label-col="labelCol" :wrapper-col="wrapperCol">
                    <a-form-item label="视频标题">
                        <a-input v-model:value="work.title" />
                    </a-form-item>
                    <a-form-item label="视频类型">
                        <a-radio-group v-model:value="work.type">
                            <a-radio value="0">原创</a-radio>
                            <a-radio value="1">转载</a-radio>
                            <a-input v-if="work.type == 1" placeholder="输入转载链接" v-model:value="work.repostUrl" />
                        </a-radio-group>
                    </a-form-item>
                    <!-- 视频分类 -->
                    <a-form-item label="视频分类" name="category">
                        <a-select v-model:value="work.categoryId" placeholder="请选择一个分类">
                            <template v-for="item in categoryList" :key="index">
                                <a-select-option :value="item.id">{{item.name}}</a-select-option>
                            </template>final
                            
                        </a-select>
                    </a-form-item>
                    <!-- 视频标签 -->
                    <a-form-item label="视频标签">
                        <template v-for="(tag, index) in state.tags" :key="tag">
                            <a-tooltip v-if="tag.length > 20" :title="tag">
                                <a-tag :closable="true" @close="handleClose(tag)">
                                    {{ `${tag.slice(0, 20)}...` }}
                                </a-tag>
                            </a-tooltip>
                            <a-tag v-else :closable="true" @close="handleClose(tag)">
                                {{ tag }}
                            </a-tag>
                        </template>
                        <a-input v-if="state.inputVisible" ref="inputRef" v-model:value="state.inputValue" type="text"
                            size="small" :style="{ width: '78px' }" @blur="handleInputConfirm"
                            @keyup.enter="handleInputConfirm" />
                        <a-tag v-else style="background: #fff; border-style: dashed" @click="showInput">
                            <plus-outlined />
                            添加
                        </a-tag>
                    </a-form-item>




                    <a-form-item label="视频简介">
                        <a-textarea v-model:value="work.description" />
                    </a-form-item>
                    <a-form-item :wrapper-col="{ span: 14, offset: 4 }">
                        <a-button type="primary" @click="postVideo" :loading="posting">投稿</a-button>
                        <a-button style="margin-left: 10px" :disabled="posting"
                            @click="fileList.length = 0">取消</a-button>
                    </a-form-item>
                </a-form>






            </template>
            <template v-if="fileList.length == 0">
                <a-upload-dragger :fileList="fileList" :max-count="1" :before-upload="beforeUpload" :multiple="false">
                    <p class="ant-upload-drag-icon">
                        <inbox-outlined></inbox-outlined>
                    </p>
                    <p class="ant-upload-text">单击或拖动视频文件到此进行上传</p>
                    <p class="ant-upload-hint">
                        视频文件最大5G，支持mp4,flv,avi,wmv,mov,webm,mpeg4,ts,mpg,rm,rmvb,mkv,m4v格式
                    </p>
                </a-upload-dragger>
                <br />
                <p style="text-align: center;">
                    <a-tooltip title="预计等待时间 1小时" color="black" placement="right">
                        当前审核队列：<a-tag color="green">快速</a-tag>
                    </a-tooltip>
                </p>
            </template>
        </div>
        <div v-show="tabActive == tab[1]">
            ssssss
        </div>
    </div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
const tab = reactive(['上传视频', '视频管理', '统计数据']);
const tabActive = ref(tab[0]);
const uploadState = ref('就绪');

//上传之前
import { InboxOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
const fileList = ref([]);
import type { UploadProps } from 'ant-design-vue';
const beforeUpload: UploadProps['beforeUpload'] = file => {
    console.log('开始处理视频。。。。。。');
    fileList.value = [...(fileList.value || []), file];
    handleUpload()
};

//投稿表单控件
import { toRaw } from 'vue';
const work = reactive({
    title: '',
    type: '0',
    description: '',
    repostUrl: '',
    tags: [],
    categoryId: null,
});

//发布视频
const posting = ref(false);
const postVideo = async () => {
    posting.value = true;
    const requestBody = toRaw(work);
    requestBody.tags = state.tags;
    requestBody.coverData = '';
    requestBody.fileMd5 = fileMd5Ref.value;
    requestBody.type = Number(requestBody.type);

    if (!requestBody.repostUrl) delete requestBody.repostUrl;

    try {
        const response = await request.post('/video', requestBody);
        fileList.value.length = 0;
    } catch (e) {

    } finally {
        posting.value = false;
    }
};
const labelCol = { style: { width: '150px' } };
const wrapperCol = { span: 14 };

//视频标签
import { nextTick } from 'vue';
import { PlusOutlined } from '@ant-design/icons-vue';

const inputRef = ref();
const state = reactive({
    tags: [],
    inputVisible: false,
    inputValue: '',
});
const handleClose = (removedTag: string) => {
    const tags = state.tags.filter(tag => tag !== removedTag);
    state.tags = tags;
};
const showInput = () => {
    state.inputVisible = true;
    nextTick(() => {
        inputRef.value.focus();
    });
};
const handleInputConfirm = () => {
    const inputValue = state.inputValue;
    let tags = state.tags;
    if (inputValue && tags.indexOf(inputValue) === -1) {
        tags = [...tags, inputValue];
    }
    console.log(tags);
    Object.assign(state, {
        tags,
        inputVisible: false,
        inputValue: '',
    });
};

//分类加载
const categoryList = ref([]);
(async () => {
    const response = await request.get('/video/category/list/all');
    categoryList.value = response.data;
})()



//开始上传
import request from '@/script/utils/request'; // 导入Axios实例
import Worker from '@/script/worker/FileMd5CalcWorker?worker';
let worker = new Worker();
const uploadPercent = ref(0);
const uploadProgressStatus = ref('active');
const fileMd5Ref = ref('');
const uploadSuccessCallback = () => {
    //上传完成
    uploadState.value = '上传完成';
    uploadPercent.value = 100;
    uploadProgressStatus.value = '';
}
const uploadFailure = () => {
    message.error('上传失败，请重新上传')
    fileList.value.length = 0;
}
const handleUpload = async () => {
    uploadPercent.value = 0
    const file = fileList.value[0];
    if (!file) return;

    work.title = file.name;

    //发送消息
    uploadState.value = '计算文件md5';
    const chunkSize = 50 * 1024 * 1024; // 50MB
    const chunkNumber = Math.ceil(file.size / chunkSize);
    worker = new Worker();
    worker.postMessage({
        file,
        chunkSize,
        chunkNumber
    });

    //接收消息
    worker.onmessage = async function (e) {
        worker.terminate();
        console.log(`文件md5计算完毕`);
        //收到整个文件的md5及各个分块
        const fileMd5 = e.data.md5;
        fileMd5Ref.value = fileMd5;
        const chunks = e.data.chunks;

        console.log('文件md5', fileMd5);
        console.log('分块', chunks);

        uploadState.value = '查询分块上传状态';
        try {
            const response = await request.post('/video/upload/checkChunks', {
                chunkSize,
                chunkNumber,
                fileMd5
            });
            if (response.code == 3_001) {
                uploadSuccessCallback({
                    fileMd5,
                });
                return;
            }

            //开始上传分块;
            console.log('检查分块完成', response);
            const tickets = response.data.tickets;
            for (let i = 1; i <= tickets.length; i++) {
                uploadState.value = `开始上传分块${i}`;
                const ticket = tickets[i - 1];
                if (!ticket) {
                    uploadPercent.value = Math.ceil(i / tickets.length * 100)
                    continue;
                }
                const formData = new FormData();

                //添加必要信息
                uploadState.value = `分块${i}: 拷贝参数`;
                for (const k in ticket) {
                    formData.append(k, ticket[k]);
                }

                //添加附加信息
                uploadState.value = `分块${i}: 添加key和Content-Type`;
                // formData.append('key', '???');
                formData.append('Content-Type', file.type);

                //添加文件
                uploadState.value = `分块${i}: 添加文件`;
                formData.append('file', chunks[i - 1].file);

                uploadState.value = `上传分块${i}`;
                try {
                    const response = await request.post('http://master:9000/video', formData);

                    try {
                        await request.post('/video/upload/setChunkMd5', {
                            chunkId: i,
                            chunkMd5: chunks[i - 1].md5,
                            fileMd5
                        });

                        uploadState.value = `分块${i}: 上传成功`;
                        uploadPercent.value = Math.ceil(i / tickets.length * 100)
                    } catch (e) {
                        uploadState.value = `分块${i}上传失败`;
                        return;
                    }
                } catch (e) {
                    uploadState.value = `分块${i}上传失败`;
                    return;
                }
            }

            //所有分块上传完毕，开始合并分块
            uploadState.value = `正在合并分块`;
            uploadPercent.value = 100
            try {
                await request.get('/video/upload/mergeChunks?fileMd5=' + fileMd5);
                //每1s轮询合并状态，成功就显示上传成功

                const checkIsMerged = async () => {
                    try {
                        const response = await request.post('/video/upload/checkChunks', {
                            chunkSize,
                            chunkNumber,
                            fileMd5
                        });
                        if (response.code == 3_001) {
                            uploadSuccessCallback({
                                fileMd5
                            });
                            return
                        } else {
                            if (response.data.tickets.every(item => item === null)) {
                                setTimeout(checkIsMerged, 1000); //轮询
                            } else {
                                uploadState.value = '上传失败，请重新上传';
                            }
                        }
                    } catch (e) {

                    }
                }
                checkIsMerged();
            } catch (e) {
                uploadState.value = `分块合并失败，请重新上传`;
                return;
            }
        } catch (e) {
            // uploadState.value = '分块状态查询失败';
        } finally {

        }
    };
}

</script>
<style scoped>
.container {
    max-width: 600px;
    margin: 0 auto;
}

.upload-component {
    background-color: #efefef;
    padding: 20px;
    border-radius: 20px;
}
</style>
